package org.locker.device.controller.admin;

import cn.dev33.satoken.secure.BCrypt;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.locker.common.core.domain.R;
import org.locker.common.core.domain.model.LoginBody;
import org.locker.common.core.domain.model.LoginUser;
import org.locker.common.core.utils.MessageUtils;
import org.locker.common.core.utils.StringUtils;
import org.locker.common.core.validate.AddGroup;
import org.locker.common.idempotent.annotation.RepeatSubmit;
import org.locker.common.mybatis.core.page.PageQuery;
import org.locker.common.satoken.utils.LoginHelper;
import org.locker.common.tenant.helper.TenantHelper;
import org.locker.device.dto.ManagerClientQueryDto;
import org.locker.device.dto.TakeBagDto;
import org.locker.device.dto.UpdatePwdDto;
import org.locker.domain.*;
import org.locker.domain.bo.DeviceOperDommandBo;
import org.locker.domain.bo.RepairBo;
import org.locker.domain.enums.DeviceStatusEnum;
import org.locker.domain.enums.OrderStatusEnum;
import org.locker.domain.vo.*;
import org.locker.netty.MachineService;
import org.locker.service.*;
import org.locker.system.domain.SysClient;
import org.locker.system.domain.vo.SysUserVo;
import org.locker.system.domain.vo.UserInfoVo;
import org.locker.system.service.ISysClientService;
import org.locker.system.service.ISysUserService;
import org.locker.web.domain.vo.LoginVo;
import org.locker.web.service.IAuthStrategy;
import org.locker.web.service.SysLoginService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 管理端controller
 *
 * @Author: lark
 * @Date: 2023/11/29
 */

@RequiredArgsConstructor
@Slf4j
@RestController
@RequestMapping("/manager")
public class ManagerClientController {

    private final ISysUserService userService;
    private final IOrderService orderService;
    private final IDeviceService deviceService;
    private final IDeviceOperateLogService deviceOperateLogService;
    private final IDeviceGridService deviceGridService;
    private final ISysClientService clientService;
    private final SysLoginService loginService;
    private final MachineService machineService;
    private final IRepairService repairService;
    private final IManagerConfigService managerConfigService;
    private final IPositionService positionService;

    private final String[] ENABLE_LOGIN_ROLES = {"superadmin", "agent_role", "position_role", "finance_role", "customer_service_role", "maintain_role"};


    /**
     * 登录方法
     *
     * @param loginBody 登录信息
     * @return 结果
     */
    @PostMapping("/login")
    public R<LoginVo> login(@Validated @RequestBody LoginBody loginBody) {
        // 授权类型和客户端id
        String clientId = loginBody.getClientId();
        String grantType = loginBody.getGrantType();
        //无线验证码登录
        loginBody.setCaptchaEnabled(false);
        SysClient client = clientService.queryByClientId(clientId);
        // 查询不到 client 或 client 内不包含 grantType
        if (ObjectUtil.isNull(client) || !StringUtils.contains(client.getGrantType(), grantType)) {
            log.info("客户端id: {} 认证类型：{} 异常!.", clientId, grantType);
            return R.fail(MessageUtils.message("auth.grant.type.error"));
        }
        // 校验租户
        loginService.checkTenant(loginBody.getTenantId());
        // 登录
        LoginVo login = IAuthStrategy.login(loginBody, client);

        //校验角色，只有超管、代理商、场地管理员才能登录管理端
        LoginUser loginUser = LoginHelper.getLoginUser();
        Set<String> rolePermission = loginUser.getRolePermission();
        boolean b = Arrays.stream(ENABLE_LOGIN_ROLES).anyMatch(role -> rolePermission.contains(role));
        if (!b) {
            return R.fail("当前用户角色无权登录！");
        }
        return R.ok(login);
    }

    /**
     * 获取用户信息
     *
     * @return
     */
    @GetMapping("/getInfo")
    public R<UserInfoVo> getInfo() {
        UserInfoVo userInfoVo = new UserInfoVo();
        LoginUser loginUser = LoginHelper.getLoginUser();
        if (TenantHelper.isEnable() && LoginHelper.isSuperAdmin()) {
            // 超级管理员 如果重新加载用户信息需清除动态租户
            TenantHelper.clearDynamic();
        }
        SysUserVo user = userService.selectUserById(loginUser.getUserId());
        if (ObjectUtil.isNull(user)) {
            return R.fail("没有权限访问用户数据!");
        }
        userInfoVo.setUser(user);
        userInfoVo.setPermissions(loginUser.getMenuPermission());
        userInfoVo.setRoles(loginUser.getRolePermission());
        return R.ok(userInfoVo);
    }

    /**
     * 修改密码
     *
     * @param updatePwdDto
     * @return
     */
    @PostMapping("/updatePwd")
    public R<Void> updatePwd(@Validated @RequestBody UpdatePwdDto updatePwdDto) {
        String oldPassword = updatePwdDto.getOldPassword();
        String newPassword = updatePwdDto.getNewPassword();
        SysUserVo user = userService.selectUserById(LoginHelper.getUserId());
        String password = user.getPassword();
        if (!BCrypt.checkpw(oldPassword, password)) {
            return R.fail("修改密码失败，旧密码错误");
        }
        if (BCrypt.checkpw(newPassword, password)) {
            return R.fail("新密码不能与旧密码相同");
        }

        if (userService.resetUserPwd(user.getUserId(), BCrypt.hashpw(newPassword)) > 0) {
            //修改成功后退出登录操作
            loginService.logout();
            return R.ok();
        }
        return R.fail("修改密码异常，请联系管理员");
    }

    /**
     * 查询订单流水
     *
     * @param queryDto
     * @param pageQuery
     * @return
     */
    @GetMapping("/queryOrderFlow")
    public R<Page<OrderFlowVo>> queryOrderFlow(ManagerClientQueryDto queryDto, PageQuery pageQuery) {
        setDataPermissions(queryDto);
        return R.ok(orderService.queryOrderFlow(queryDto, pageQuery));
    }


    /**
     * 查询设备列表
     */
    @GetMapping("/deviceList")
    public R<Page<DeviceVo>> deviceList(ManagerClientQueryDto queryDto, PageQuery pageQuery) {
        setDataPermissions(queryDto);
        queryDto.setIsQueryOrder(true);
        return R.ok(deviceService.listByManagerClient(queryDto, pageQuery));
    }

    /**
     * 根据设备id查询设备详情
     *
     * @param id
     * @return
     */
    @GetMapping("/getDeviceById")
    public R<DeviceVo> getDeviceById(@RequestParam("id") Long id) {
        DeviceVo deviceVo = deviceService.queryById(id);
        if (ObjectUtil.isNotNull(deviceVo)) {
            List<DeviceGrid> deviceGrids = deviceGridService.selectByDeviceId(id);
            deviceVo.setDeviceGridList(deviceGrids);
        }
        return R.ok(deviceVo);
    }

    /**
     * 查询离线设备信息
     */
    @GetMapping("/offLineDevice")
    public R<Page<DeviceVo>> offLineDevice(ManagerClientQueryDto queryDto, PageQuery pageQuery) {
        setDataPermissions(queryDto);
        queryDto.setDeviceStatus(DeviceStatusEnum.offline.getCode());
        queryDto.setIsQueryOrder(true);
        return R.ok(deviceService.listByManagerClient(queryDto, pageQuery));
    }

    /**
     * 我的设备流水
     *
     * @param queryDto
     * @param pageQuery
     * @return
     */
    @GetMapping("/queryDeviceFlow")
    public R<Page<DeviceFlowVo>> queryDeviceFlow(ManagerClientQueryDto queryDto, PageQuery pageQuery) {
        setDataPermissions(queryDto);
        Page<DeviceFlowVo> deviceFlowVoPage = orderService.queryDeviceFlow(queryDto, pageQuery);
        LoginUser loginUser = LoginHelper.getLoginUser();
        Set<String> rolePermission = loginUser.getRolePermission();
        String role = rolePermission.stream().findFirst().get();
        boolean no_refuse = Arrays.stream(NO_REFUSE_DATA_ROLES).anyMatch(roleName -> roleName.equals(role));
        //只有管理员权限和场地管理员才能够有金额显示
        if (!no_refuse) {
            deviceFlowVoPage.getRecords().forEach(item -> {
                if (item.getAmount() != null) {
                    item.setAmount(BigDecimal.ZERO);
                }
                if (item.getTjAmount() != null) {
                    item.setTjAmount(BigDecimal.ZERO);
                }
            });
        }
        return R.ok(deviceFlowVoPage);
    }

    /**
     * 我的场地流水
     *
     * @param queryDto
     * @param pageQuery
     * @return
     */
    @GetMapping("/queryPositionFlow")
    public R<Page<PositionFlowVo>> queryPositionFlow(ManagerClientQueryDto queryDto, PageQuery pageQuery) {
        setDataPermissions(queryDto);

        Page<PositionFlowVo> positionFlowVoPage = orderService.queryPositionFlow(queryDto, pageQuery);
        LoginUser loginUser = LoginHelper.getLoginUser();
        Set<String> rolePermission = loginUser.getRolePermission();
        String role = rolePermission.stream().findFirst().get();
        boolean no_refuse = Arrays.stream(NO_REFUSE_DATA_ROLES).anyMatch(roleName -> roleName.equals(role));
        //只有管理员权限和场地管理员才能够有金额显示
        if (!no_refuse) {
            positionFlowVoPage.getRecords().forEach(item -> {
                if (item.getAmount() != null) {
                    item.setAmount(BigDecimal.ZERO);
                }
                if (item.getTjAmount() != null) {
                    item.setTjAmount(BigDecimal.ZERO);
                }
            });
        }
        return R.ok(positionFlowVoPage);
    }

    /**
     * 只有管理员权限和场地管理员才能够有金额显示
     */
    private final String[] NO_REFUSE_DATA_ROLES = {"superadmin","agent_role"};

    /**
     * 统计
     *
     * @param queryDto
     * @return
     */
    @GetMapping("/statistics")
    public R<StatisticsVo> statistics(ManagerClientQueryDto queryDto) {
        setDataPermissions(queryDto);
        StatisticsVo statistics = orderService.statistics(queryDto);
        LoginUser loginUser = LoginHelper.getLoginUser();
        Long userId = loginUser.getUserId();
        Set<String> rolePermission = loginUser.getRolePermission();
        String role = rolePermission.stream().findFirst().get();
        boolean no_refuse = Arrays.stream(NO_REFUSE_DATA_ROLES).anyMatch(roleName -> roleName.equals(role));
        //只有管理员权限和场地管理员才能够有金额显示
        if (!no_refuse) {
            statistics.setTotalAmount(BigDecimal.ZERO);
            statistics.setTodayAmount(BigDecimal.ZERO);
            statistics.setTodayTjAmount(BigDecimal.ZERO);
            statistics.setYesterdayAmount(BigDecimal.ZERO);
        }
        statistics.setTodayUnrefundAmount(BigDecimal.ZERO);
        statistics.setUnrefundOrderAmount(BigDecimal.ZERO);
        if (statistics.getDailyOrderVoList() != null) {
            statistics.getDailyOrderVoList().stream().forEach(a -> {
                a.setUnrefundOrderAmount(BigDecimal.ZERO);
            });
        }
        return R.ok(statistics);
    }

    /**
     * 根据区域查询场地列表
     *
     * @param queryDto
     * @return
     */
    @GetMapping("/getPositionByBelongingPlace")
    public R<List<Position>> getPositionByBelongingPlace(ManagerClientQueryDto queryDto) {
        setDataPermissions(queryDto);
        List<Long> positionIdList = queryDto.getPositionIdList();
        // 获取符合区域条件的位置列表
        List<Position> list = positionService.list(
            Wrappers.<Position>lambdaQuery()
                .like(StrUtil.isNotBlank(queryDto.getBelongingPlaceStr()), Position::getBelongingPlaceStr, queryDto.getBelongingPlaceStr())
                .in(CollUtil.isNotEmpty(positionIdList), Position::getPositionId, positionIdList));
        return R.ok(list);
    }


    /**
     * 查询设备操作流水
     *
     * @param queryDto
     * @param pageQuery
     * @return
     */
    @GetMapping("/deviceOperLog")
    public R<Page<DeviceOperateLogVo>> deviceOperLog(ManagerClientQueryDto queryDto, PageQuery pageQuery) {
        setDataPermissions(queryDto);
        pageQuery.setOrderByColumn("create_time");
        pageQuery.setIsAsc("desc");
        return R.ok(deviceOperateLogService.deviceOperLog(queryDto, pageQuery));
    }

    /**
     * 根据设备号统计订单数据(按年或者月或者日)
     */
    @GetMapping("/getOrderNumByDeviceId")
    public R<List<Map<String, Integer>>> getOrderNumByDeviceId(ManagerClientQueryDto queryDto) {
        setDataPermissions(queryDto);
        return R.ok(orderService.getOrderNumByDeviceId(queryDto));
    }


    /**
     * 设备指令
     *
     * @param operDommandBo
     * @return
     */
    @PostMapping("/operDommand")
    public R operDommand(@Validated @RequestBody DeviceOperDommandBo operDommandBo) {
        String code = operDommandBo.getOperType();
        String deviceNo = operDommandBo.getDeviceNo();
        Device device = deviceService.queryByDeviceNo(deviceNo);
        if (device != null && device.getStatus() != null) {
            if (!device.getStatus().equals(DeviceStatusEnum.online.getCode())) {
                return R.fail("设备不在线,无法发送指令。");
            }
        }

        switch (code) {
            case "2" -> {
                //重启设备
                machineService.restartDevice(deviceNo);
            }
            case "3" -> {
                machineService.setDevicePosition(deviceNo);
            }
            case "4" -> {
                //一键全开
                machineService.controlOpenAll(deviceNo);
            }
            case "5" -> {
                //同步全部格子状态
                machineService.synchronousGridList(deviceNo);
            }
            case "7" -> {
                machineService.deviceCommonInfoSync(deviceNo);

            }
            case "12" -> {
                //获取设备SIM卡信息
                machineService.getSimInfo(deviceNo);

            }
            case "13" -> {
                //进入后台
                machineService.adminExec(deviceNo);

            }

            default -> throw new IllegalStateException("Unexpected deviceNo: " + code);
        }
        return R.ok();
    }


    /**
     * 按日查询订单信息
     *
     * @param queryDto
     * @param pageQuery
     * @return
     */
    @GetMapping("/queryOrderByDay")
    public R<Page<OrderDetailVo>> queryOrderByDay(ManagerClientQueryDto queryDto, PageQuery pageQuery) {
        setDataPermissions(queryDto);
        return R.ok(orderService.queryOrderByDay(queryDto, pageQuery));
    }


    /**
     * 开锁
     *
     * @param deviceGridId
     * @return
     */
    @PostMapping("/open/{deviceGridId}")
    public R<Void> open(@NotEmpty(message = "格子id不能为空")
                        @PathVariable Long deviceGridId) {
        Long[] deviceGridIds = {deviceGridId};
        deviceGridService.open(deviceGridIds);
        return R.ok();
    }

    /**
     * desc: 结束订单
     *
     * @param deviceGridId
     * @return
     */
    @GetMapping("/close/{deviceGridId}")
    public R<OrderVo> close(@NotNull(message = "订单ID不能为空")
                            @PathVariable Long deviceGridId) {
        //获取正在进行的订单
        Order order = orderService.getOne(Wrappers.<Order>lambdaQuery()
            .eq(Order::getDeviceGridId, deviceGridId).in(Order::getOrderStatus, OrderStatusEnum.getActiveStatusList()));
        if (ObjectUtil.isNull(order)) {
            return R.fail("该柜子不存在订单");
        }
        orderService.close(order, true,false);
        return R.ok();
    }

    /**
     * 根据柜id查询订单
     *
     * @param deviceGridId
     * @return
     */
    @GetMapping("/getOrder/{deviceGridId}")
    public R<OrderVo> getOrderByGridId(@NotNull(message = "柜子ID不能为空")
                                       @PathVariable Long deviceGridId) {
        //获取正在进行的订单
        Order order = orderService.getOne(Wrappers.<Order>lambdaQuery()
            .eq(Order::getDeviceGridId, deviceGridId).in(Order::getOrderStatus, OrderStatusEnum.getActiveStatusList()));
        if (ObjectUtil.isNull(order)) {
            return R.ok();
        } else {
            OrderVo orderVo = orderService.queryById(order.getOrderId());
            return R.ok(orderVo);
        }
    }


    /**
     * 新增报修
     *
     * @param bo
     * @return
     */
    @RepeatSubmit()
    @PostMapping("/addRepair")
    public R addRepair(@Validated(AddGroup.class) @RequestBody RepairBo bo) {
        bo.setUserId(LoginHelper.getUserId());
        repairService.insertByBo(bo);
        return R.ok();
    }


    /**
     * 协助取包
     *
     * @param dto
     * @return
     */
    @PostMapping("/takeBag")
    public R takeBag(@Validated @RequestBody TakeBagDto dto) {
        String phone = dto.getPhone();
        String openPwd = dto.getOpenPwd();
        //根据手机号和密码找到订单
        Order one = orderService.getOne(Wrappers.<Order>lambdaQuery().eq(Order::getOpenPwd, openPwd).eq(Order::getPhone, phone)
            .eq(Order::getOrderStatus, OrderStatusEnum.IN_USED.getCode()));
        if (ObjectUtil.isNotNull(one)) {
            Long[] deviceGridIds = {one.getDeviceGridId()};
            //开锁处理
            deviceGridService.open(deviceGridIds);


        } else {
            R.fail("未找到订单!");
        }

        return R.ok();
    }


    /**
     * 设置数据权限
     *
     * @param queryDto
     */
    private void setDataPermissions(ManagerClientQueryDto queryDto) {
        LoginUser loginUser = LoginHelper.getLoginUser();
        Long userId = loginUser.getUserId();
        Set<String> rolePermission = loginUser.getRolePermission();
        String s = rolePermission.stream().findFirst().get();
        queryDto.setRoleKey(s);

        List<Long> positionIdList = new ArrayList<Long>();
        if ("superadmin".equalsIgnoreCase(s)) {
            return;
        }

        if ("agent_role".equalsIgnoreCase(s)) {
            List<ManagerConfig> list = managerConfigService.list(Wrappers.<ManagerConfig>lambdaQuery().eq(ManagerConfig::getParentManagerId, userId));
            positionIdList = list.stream().map(ManagerConfig::getPositionId).collect(Collectors.toList());
        }

        if ("position_role".equalsIgnoreCase(s)) {
            List<ManagerConfig> list = managerConfigService.list(Wrappers.<ManagerConfig>lambdaQuery().eq(ManagerConfig::getManagerId, userId));
            positionIdList = list.stream().map(ManagerConfig::getPositionId).collect(Collectors.toList());
        }

        if ("finance_role".equalsIgnoreCase(s)) {
            List<Position> list = positionService.list(Wrappers.<Position>lambdaQuery().eq(Position::getFinanceUserId, userId));
            positionIdList = list.stream().map(Position::getPositionId).collect(Collectors.toList());
        }

        if ("maintain_role".equalsIgnoreCase(s)) {
            List<Position> list = positionService.list(Wrappers.<Position>lambdaQuery().eq(Position::getDeviceUserId, userId));
            positionIdList = list.stream().map(Position::getPositionId).collect(Collectors.toList());
        }
        if (CollUtil.isEmpty(positionIdList)) {
            positionIdList.add(-1L);
        } else {
            //参数带的场地id
            List<Long> positionIdList1 = queryDto.getPositionIdList();
            if (CollUtil.isNotEmpty(positionIdList1)) {
                //取交集
                positionIdList.retainAll(positionIdList1);
            }
        }
        queryDto.setPositionIdList(positionIdList);

        //更具场地查找设备
        List<Device> list = deviceService.list(Wrappers.<Device>lambdaQuery().in(CollUtil.isNotEmpty(positionIdList), Device::getPositionId, positionIdList));
        if (CollUtil.isNotEmpty(list)) {
            List<Long> deviceIdList = list.stream().map(Device::getDeviceId).collect(Collectors.toList());
            List<String> deviceNoList = list.stream().map(Device::getDeviceNo).collect(Collectors.toList());
            queryDto.setDeviceNoList(deviceNoList);
            queryDto.setDeviceIdList(deviceIdList);
        } else {
            ArrayList<Long> deviceIdList = new ArrayList<>();
            deviceIdList.add(-1L);

            ArrayList<String> deviceNoList = new ArrayList<>();
            deviceNoList.add("-1");
            queryDto.setDeviceNoList(deviceNoList);
            queryDto.setDeviceIdList(deviceIdList);

        }

    }


}
